From 981b1cd65efb4483fe9f44e568a78a0972b4c9b0 Mon Sep 17 00:00:00 2001 From: oliskoli Date: Sat, 18 Oct 2008 21:34:21 +0000 Subject: [PATCH] Add support for Memory-Map Navigator Overlay files (.mmo). --- Makefile.in | 4 +- mmo.c | 1238 +++++++++++++ reference/memory-map.mmo | Bin 0 -> 21552 bytes reference/memory-map~mmo.gpx | 3180 ++++++++++++++++++++++++++++++++++ vecs.c | 7 + 5 files changed, 4428 insertions(+), 1 deletion(-) create mode 100644 mmo.c create mode 100755 reference/memory-map.mmo create mode 100644 reference/memory-map~mmo.gpx diff --git a/Makefile.in b/Makefile.in index 701672320..071c13f33 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,7 +61,7 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \ ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \ navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \ igo8.o gopal.o humminbird.o mapasia.o gnav_trl.o navitel.o ggv_ovl.o \ - jtr.o sbp.o + jtr.o sbp.o mmo.o FMTS=@FMTS@ @@ -638,6 +638,8 @@ mapsource.o: mapsource.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpsinput.h jeeps/gpsproj.h mkshort.o: mkshort.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h +mmo.o: mmo.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h avltree.h msroute.o: msroute.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h \ jeeps/gpsmath.h jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h \ diff --git a/mmo.c b/mmo.c new file mode 100644 index 000000000..5bbcfaded --- /dev/null +++ b/mmo.c @@ -0,0 +1,1238 @@ +/* + + Support for Memory-Map Navigator Overlay Files (.mmo) + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +/* + History: + + 2008/10/18: Initial release +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "avltree.h" + +#define MYNAME "mmo" + +// #define MMO_DBG + +static +arglist_t mmo_args[] = { + ARG_TERMINATOR +}; + +typedef struct mmo_data_s { + int objid; /* internal object id */ + char *name; + const char *category; /* currently not handled */ + gpsdata_type type; /* type of "data" */ + time_t ctime; + time_t mtime; + int left; /* number of un-readed route points */ + int done; /* number of completely loaded route points */ + void *data; /* can be a waypoint, a route or a track */ + unsigned char visible:1; + unsigned char locked:1; + unsigned char loop:1; /* loop flag */ +} mmo_data_t; + +static gbfile *fin, *fout; +static int mmo_version; +static int mmo_obj_ct; +static int mmo_object_id; +static gbuint32 mmo_filemark; +static gbuint16 wpt_object_id; +static gbuint16 rte_object_id; +static gbuint16 trk_object_id; +static gbuint16 cat_object_id; +static gbuint16 ico_object_id; +static gbuint16 pos_object_id; +static gbuint16 txt_object_id; +static gpsdata_type mmo_datatype; +static route_head *mmo_rte; + +static avltree_t *category_names, *objects, *mmobjects, *category_ids; +static avltree_t *icons; + +typedef struct mmo_icon_mapping_s { + const int value; + const char *icon; +} mmo_icon_mapping_t; + +/* standard icons; no bitmaps in file */ + +static const mmo_icon_mapping_t mmo_icon_value_table[] = { + { 0x00, "Dot" }, + { 0x01, "House" }, + { 0x02, "Fuel" }, + { 0x03, "Car" }, + { 0x04, "Fish" }, + { 0x05, "Boat" }, + { 0x06, "Anchor" }, + { 0x07, "Wreck" }, + { 0x08, "Exit" }, + { 0x09, "Skull" }, + { 0x0A, "Flag" }, + { 0x0B, "Camp" }, + { 0x0C, "Man Overboard" }, + { 0x0D, "Deer" }, + { 0x0E, "First Aid" }, + { 0x0F, "Trackback" }, + { 0x10, "Tiny dot" }, + { 0x11, "Triangle" }, + { 0x12, "Square" }, + { 0x13, "Circle" }, + { 0x14, "Green bouy" }, + { 0x15, "Red bouy" }, + { 0x16, "Yellow bouy" }, + { 0x17, "Geocache" }, + + { -1, NULL } +}; + +/* helpers */ + +#ifdef MMO_DBG +static void +dbgprintf(const char *sobj, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + printf(MYNAME "-%s: ", sobj); + vprintf(fmt, args); + va_end(args); +} + +# define DBG(args) dbgprintf args +#else +# define DBG(args) ; +#endif + +static char * +mmo_readstr(void) +{ + char *res; + int len; + + len = (unsigned)gbfgetc(fin); + if (len == 0xFF) { + len = gbfgetint16(fin); + if (len < 0) fatal(MYNAME ": Invalid string length (%d)!\n", len); + } + res = xmalloc(len + 1); + res[len] = '\0'; + if (len) { + gbfread(res, len, 1, fin); + if (len != strlen(res)) fatal(MYNAME ": Error in file structure!\n"); + } + + return res; +} + + +static int +mmo_fillbuf2(void *buf, const gbsize_t bufsz, const int count, const int need_all) +{ + int res; + + if (count > bufsz) fatal(MYNAME ": Internal error (bufsz too small)!\n"); + + memset(buf, 0xFF, count); + res = gbfread(buf, 1, count, fin); + if (need_all && (res < count)) fatal(MYNAME ": Unexpected end of file!\n"); + + return res; +} +#define mmo_fillbuf(a,b,c) mmo_fillbuf2((a),sizeof((a)),(b),(c)) + +static void +mmo_printbuf(const char *buf, int count, const char *comment) +{ +#ifdef MMO_DBG + int i; + printf("%s", comment); + for (i = 0; i < count; i++) printf("%02X ", buf[i] & 0xFF); + printf("- "); + for (i = 0; i < count; i++) + if (isprint(buf[i])) printf("%c", buf[i] & 0xFF); + else printf("."); + printf("\n"); + fflush(stdout); +#endif +} + +/******************************************************************************/ + +static mmo_data_t * +mmo_register_object(const int objid, const void *ptr, const gpsdata_type type) +{ + char key[16]; + mmo_data_t *data; + + data = xcalloc(1, sizeof(*data)); + data->data = (void *)ptr; + data->visible = 1; + data->locked = 0; + data->type = type; + data->objid = objid; + + snprintf(key, sizeof(key), "%d", objid); + avltree_insert(objects, key, data); + + return data; +} + + +static int +mmo_get_objid(const void *ptr) +{ + const char *key; + mmo_data_t *data; + + if ((key = avltree_first(objects, (void *)&data))) do { + if (data->data == ptr) { + return atoi(key); + } + } while ((key = avltree_next(objects, key, (void *)&data))); + + return 0; +} + + +static mmo_data_t * +mmo_get_object(const gbuint16 objid) +{ + char key[16]; + mmo_data_t *data; + + snprintf(key, sizeof(key), "%d", objid | 0x8000); + if (! avltree_find(objects, key, (void *)&data)) + fatal(MYNAME ": Unregistered object id 0x%04X!\n", objid | 0x8000); + + return data; +} + + +static void +mmo_release_avltree(avltree_t *tree, const int is_object) +{ + const char *key; + char *name; + + if ((key = avltree_first(tree, (void *)&name))) { + do { + if (name == NULL) continue; + if (is_object) { + mmo_data_t *data = (mmo_data_t *)name; + if (data->name) xfree(data->name); + } + xfree(name); + } while ((key = avltree_next(tree, key, (void *)&name))); + } + avltree_done(tree); +} + + +static void +mmo_register_icon(const int id, const char *name) +{ + char key[16]; + + snprintf(key, sizeof(key), "%d", id); + avltree_insert(icons, key, xstrdup(name)); +} + + +static mmo_data_t *mmo_read_object(const waypoint *add); + + +static void +mmo_end_of_route(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjRoute"; +#endif + route_head *rte = data->data; + int rtept = rte->rte_waypt_ct; + int i; + char buf[64]; + + if (data->visible && data->loop) { + DBG((sobj, "route \"%s\" is a loop.\n", data->name)); + (void) mmo_read_object(NULL); + rtept--; + } + + if (mmo_version >= 0x12) { + mmo_fillbuf(buf, 7, 1); + DBG((sobj, "route data (since 0x12): ")); + mmo_printbuf(buf, 7, ""); + + rte->line_color.bbggrr = le_read32(&buf[0]); + rte->line_color.opacity = 255 - (buf[6] * 51); + DBG((sobj, "color = 0x%06X\n", rte->line_color.bbggrr)); + DBG((sobj, "transparency = %d (-> %d)\n", buf[6], rte->line_color.opacity)); + } + + if (data->visible) { + for (i = 0; i < rtept; i++) (void) mmo_read_object(NULL); + } + if (data->loop && (data->done > 1)) { + queue *elem; + + elem = QUEUE_FIRST(&rte->waypoint_list); + dequeue(elem); + ENQUEUE_TAIL(&rte->waypoint_list, elem); + } + + if (rte->rte_waypt_ct == 0) { /* don't keep empty routes */ + route_del_head(rte); + data->data = NULL; + } +} + + +static void +mmo_read_category(mmo_data_t *data) +{ + int marker = gbfgetuint16(fin); + + if (marker & 0x8000) { + mmo_data_t *tmp; + + gbfseek(fin, -2, SEEK_CUR); + tmp = mmo_read_object(NULL); + if (data) data->category = tmp->name; + } +} + + +static void +mmo_read_CObjIcons(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjIcons"; +#endif + int i; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + gbfseek(fin, 6, SEEK_CUR); /* skip 6 unknown bytes */ + + while ((i = gbfgetuint32(fin))) { + char *name; + (void) gbfgetuint32(fin); + (void) gbfgetuint32(fin); + name = mmo_readstr(); +// DBG((sobj, "bitmap(%d) = \"%s\"\n", i, name)); + mmo_register_icon(i, name); + xfree(name); + gbfseek(fin, gbfgetuint32(fin), SEEK_CUR); + } +} + + +static void +mmo_read_CObjWaypoint(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjWaypoint"; +#endif + waypoint *wpt; + time_t time; + int rtelinks; + mmo_data_t **rtelink = NULL; + char *str; + char buf[16]; + int i, ux; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + wpt = waypt_new(); + wpt->shortname = xstrdup(data->name); + + time = data->mtime; + if (! time) time = data->ctime; + if (time > 0) wpt->creation_time = time; + + wpt->latitude = gbfgetdbl(fin); + wpt->longitude = gbfgetdbl(fin); + + DBG((sobj, "coordinates = %f / %f\n", wpt->latitude, wpt->longitude)); + + rtelinks = gbfgetuint16(fin); + if (rtelinks > 0) { + + rtelink = xcalloc(sizeof(*rtelink), rtelinks); + DBG((sobj, "rtelinks = %d\n", rtelinks)); + + for (i = 0; i < rtelinks; i++) { + mmo_data_t *tmp; + int objid; + + DBG((sobj, "read rtelink number %d\n", i + 1)); + + objid = gbfgetuint16(fin); + gbfseek(fin, -2, SEEK_CUR); + + rtelink[i] = tmp = mmo_read_object(wpt); + + if ((objid < 0x8000) && (tmp != NULL) && (tmp->type == rtedata)) { + route_head *rte = tmp->data; + + tmp->left--; + route_add_wpt(rte, waypt_dupe(wpt)); + + DBG((sobj, "\"%s\" Added to route \"%s\"\n", wpt->shortname, rte->rte_name)); + } + } + + } + + str = mmo_readstr(); /* descr + url */ + if (strncmp(str, "_FILE_ ", 7) == 0) { + char *cx, *cend; + + cx = lrtrim(str + 7); + cend = strchr(cx, '\n'); + if (cend == NULL) cend = cx + strlen(cx); + + cx = lrtrim(xstrndup(cx, cend - cx)); + if (*cx) wpt->url = cx; + else xfree(cx); + + if (*cend++) wpt->notes = xstrdup(cend); + + if (wpt->url) DBG((sobj, "url = \"%s\"\n", wpt->url)); + } + else + if (*str) wpt->notes = xstrdup(str); + xfree(str); + + if (wpt->notes) DBG((sobj, "notes = \"%s\"\n", wpt->notes)); + + mmo_fillbuf(buf, 12, 1); + i = le_read32(&buf[8]); /* icon */ + if (i != -1) { + char key[16]; + char *name; + + snprintf(key, sizeof(key), "%d", i); + if (avltree_find(icons, key, (void *)&name)) { + wpt->icon_descr = xstrdup(name); + wpt->wpt_flags.icon_descr_is_dynamic = 1; + DBG((sobj, "icon = \"%s\"\n", wpt->icon_descr)); + } + } + + wpt->proximity = le_read_float(&buf[4]); + if (wpt->proximity) { + wpt->wpt_flags.proximity = 1; + DBG((sobj, "proximity = %f\n", wpt->proximity)); + } + + str = mmo_readstr(); /* name on gps ??? option ??? */ + if (*str) { + wpt->description = wpt->shortname; + wpt->shortname = str; + DBG((sobj, "name on gps = %s\n", str)); + } + else xfree(str); + + ux = gbfgetuint32(fin); + DBG((sobj, "proximity type = %d\n", ux)); + + if (rtelinks) { + int i; + + for (i = 0; i < rtelinks; i++) { + int j; + route_head *rte = rtelink[i]->data; + + for (j = 0; j < rtelinks; j++) { + if ((i != j) && (rtelink[i] == rtelink[j])) { + rtelink[i]->loop = 1; + break; + } + } + rtelink[i]->done++; + if ((rtelink[i]->left == 0) && (rtelink[i]->done == rte->rte_waypt_ct)) { + if (mmo_version <= 0x11) mmo_end_of_route(rtelink[i]); + } + } + } + + if (rtelink) { + xfree(rtelink); + waypt_free(wpt); + data->data = NULL; + } + else waypt_add(wpt); +} + + +static void +mmo_read_CObjRoute(mmo_data_t *data, const waypoint *add) +{ +#ifdef MMO_DBG + const char *sobj = "CObjRoute"; +#endif + int rtept; + route_head *rte; + char buf[16]; + int ux; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + data->data = rte = route_head_alloc(); + rte->rte_name = xstrdup(data->name); + route_add_head(rte); + + ux = gbfgetc(fin); /* line label */ + DBG((sobj, "line label = %d\n", ux)); + + data->left = rtept = gbfgetint16(fin); + DBG((sobj, "route has %d point(s)\n", rtept)); + + if ((data->left <= 0) && (mmo_version >= 0x12)) { + mmo_fillbuf(buf, 7, 1); + } + + if (add) { /* waypoint loaded before route */ + route_add_wpt(rte, waypt_dupe(add)); + data->left--; + } + + while (data->left > 0) { + (void) mmo_read_object(NULL); + } + + if ((mmo_version > 0x11) && (data->done > 0)) mmo_end_of_route(data); +} + + +static void +mmo_read_CObjTrack(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjTrack"; +#endif + int tp, ctp; + route_head *trk; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + trk = route_head_alloc(); + trk->rte_name = xstrdup(data->name); + track_add_head(trk); + + tp = gbfgetint16(fin); + DBG((sobj, "track has %d point(s)\n", tp)); + + for (ctp = 0; ctp < tp; ctp++) { + waypoint *wpt; + char unk; + + wpt = waypt_new(); + + wpt->latitude = gbfgetdbl(fin); + wpt->longitude = gbfgetdbl(fin); + unk = gbfgetc(fin); + + wpt->creation_time = gbfgetint32(fin); + wpt->altitude = gbfgetflt(fin); + + if (unk != 0) { + gbuint16 ux; + ux = gbfgetuint16(fin); + DBG((sobj, "u16 = %04X (%d)\n", ux, ux)); + if (unk > 1) { + gbuint16 ux; + ux = gbfgetuint16(fin); + DBG((sobj, "u16 = %04X (%d)\n", ux, ux)); + } + } + track_add_wpt(trk, wpt); + } + + if (mmo_version > 0) { + gbuint32 u32; + + u32 = gbfgetuint32(fin); /* Min. update interval */ + DBG((sobj, "min. update interval = %d\n", u32)); + u32 = gbfgetuint32(fin); /* unknown */ +// DBG((sobj, "unknown value = 0x%8X (%d)\n", u32, u32)); + u32 = gbfgetuint32(fin); /* unknown */ +// DBG((sobj, "unknown value = 0x%8X (%d)\n", u32, u32)); + u32 = gbfgetuint32(fin); /* unknown */ + DBG((sobj, "min. update distance = %d\n", u32)); + u32 = gbfgetuint32(fin); /* unknown */ + DBG((sobj, "track partition interval = %d\n", u32 / 60)); + u32 = gbfgetuint32(fin); /* unknown */ +// DBG((sobj, "unknown value = 0x%8X (%d)\n", u32, u32)); + u32 = gbfgetuint32(fin); /* unknown */ + DBG((sobj, "tick interval = %d\n", u32 / 60)); + trk->line_color.bbggrr = gbfgetuint32(fin); /* rgb color */ + trk->line_color.opacity = 255; + DBG((sobj, "color = 0x%06X\n", trk->line_color.bbggrr)); + } + + if (mmo_version >= 0x12) { + char u8; + + u8 = gbfgetc(fin); + DBG((sobj, "line width = %d - (since 0x12)\n", u8)); + u8 = gbfgetc(fin); + DBG((sobj, "line style = %d - (since 0x12)\n", u8)); + u8 = gbfgetc(fin); + DBG((sobj, "transparency = %d - (since 0x12)\n", u8)); + trk->line_color.opacity = 255 - (u8 * 51); + + if (mmo_version >= 0x16) { + char u8; + gbuint16 u16; + + u8 = gbfgetc(fin); +// DBG((sobj, "u8 = 0x%X (since 0x16)\n", u8)); + u16 = gbfgetuint16(fin); +// DBG((sobj, "u16 = 0x%X (since 0x16)\n", u16)); + u16 = gbfgetuint16(fin); +// DBG((sobj, "u16 = 0x%X (since 0x16)\n", u16)); + } + } + + if (trk->rte_waypt_ct == 0) { + track_del_head(trk); + data->data = NULL; + } +} + + +static void +mmo_read_CObjText(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjText"; +#endif + int i; + char buf[512]; + double lat, lon; + char *text, *font; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + lat = gbfgetdbl(fin); + lon = gbfgetdbl(fin); + DBG((sobj, "coordinates = %f / %f\n", lat, lon)); + + text = mmo_readstr(); + DBG((sobj, "text = \"%s\"\n", text)); + xfree(text); + + mmo_fillbuf(buf, 28, 1); + + font = mmo_readstr(); + DBG((sobj, "font = \"%s\"\n", font)); + xfree(font); + + i = mmo_fillbuf(buf, 25, 1); +// mmo_printbuf(buf, i, "CObjText\n"); +} + + +static void +mmo_read_CObjCurrentPosition(mmo_data_t *data) +{ +#ifdef MMO_DBG + const char *sobj = "CObjCurrentPosition"; +#endif + char buf[24]; + double lat, lon; + + DBG((sobj, ":-----------------------------------------------------\n")); + DBG((sobj, "name = \"%s\" [ visible=%s, id=0x%04X ]\n", + data->name, data->visible ? "yes" : "NO", data->objid)); + + lat = gbfgetdbl(fin); + lon = gbfgetdbl(fin); + DBG((sobj, "coordinates = %f / %f\n", lat, lon)); + + mmo_fillbuf(buf, 24, 1); + + if (mmo_version >= 0x14) { + char *name; + + name = mmo_readstr(); + DBG((sobj, "name = \"%s\"\n", name)); + xfree(name); + mmo_fillbuf(buf, 13, 1); + } +} + + +static mmo_data_t * +mmo_read_object(const waypoint *add) +{ + int objid; + mmo_data_t *data = NULL; + + objid = gbfgetuint16(fin); + if (objid == 0xFFFF) { + gbuint16 version; + char *sobj; + int len; + + objid = mmo_object_id++; + + version = gbfgetuint16(fin); + is_fatal(version != mmo_version, MYNAME ": Invalid version identifier!\n"); + + len = gbfgetint16(fin); + + sobj = xmalloc(len + 1); + sobj[len] = '\0'; + gbfread(sobj, len, 1, fin); + + if (strcmp(sobj, "CObjIcons") == 0) ico_object_id = objid; + else if (strcmp(sobj, "CCategory") == 0) cat_object_id = objid; + else if (strcmp(sobj, "CObjWaypoint") == 0) wpt_object_id = objid; + else if (strcmp(sobj, "CObjRoute") == 0) rte_object_id = objid; + else if (strcmp(sobj, "CObjTrack") == 0) trk_object_id = objid; + else if (strcmp(sobj, "CObjCurrentPosition") == 0) pos_object_id = objid; + else if (strcmp(sobj, "CObjText") == 0) txt_object_id = objid; + else + fatal(MYNAME ": Unknown Object \"%s\"!\n", sobj); + xfree(sobj); + } + + if (objid & 0x8000) { + + data = mmo_register_object(mmo_object_id++, NULL, 0); + data->name = mmo_readstr(); + + if (objid != cat_object_id) { + data->ctime = gbfgetuint32(fin); + data->mtime = gbfgetuint32(fin); + data->locked = gbfgetc(fin); + data->visible = gbfgetc(fin); + (void) gbfgetuint16(fin); + (void) gbfgetuint16(fin); + + if (objid != ico_object_id) mmo_read_category(data); + } + + if (objid == cat_object_id) ; /* do nothing */ + else if (objid == ico_object_id) mmo_read_CObjIcons(data); + else if (objid == trk_object_id) { + data->type = trkdata; + mmo_read_CObjTrack(data); + } + else if (objid == wpt_object_id) { + data->type = wptdata; + mmo_read_CObjWaypoint(data); + } + else if (objid == rte_object_id) { + data->type = rtedata; + mmo_read_CObjRoute(data, add); + } + else if (objid == pos_object_id) mmo_read_CObjCurrentPosition(data); + else if (objid == txt_object_id) mmo_read_CObjText(data); + else + fatal(MYNAME ": Unregistered Object-ID 0x%04X\n", objid); + } + else data = mmo_get_object(objid); + + return data; +} + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +mmo_rd_init(const char *fname) +{ + int i; + + fin = gbfopen_le(fname, "rb", MYNAME); + + category_ids = avltree_init(0, MYNAME); + objects = avltree_init(0, MYNAME); + icons = avltree_init(0, MYNAME); + + ico_object_id = pos_object_id = txt_object_id = cat_object_id = 0; + wpt_object_id = rte_object_id = trk_object_id = 0; + + mmo_object_id = 0x8001; + + i = 0; + while (mmo_icon_value_table[i].icon) { + mmo_register_icon(mmo_icon_value_table[i].value, mmo_icon_value_table[i].icon); + i++; + } +} + + +static void +mmo_rd_deinit(void) +{ + mmo_release_avltree(icons, 0); + mmo_release_avltree(category_ids, 0); + mmo_release_avltree(objects, 1); + gbfclose(fin); +} + + +static void +mmo_read(void) +{ +#ifdef MMO_DBG + const char *sobj = "main"; +#endif + gbfile *fx; + int i; + + /* copy file to memory stream (needed for seek-ops and piped commands) */ + + DBG(("main", "loading file \"%s\".\n", fin->name)); + + fx = gbfopen(NULL, "wb", MYNAME); + gbfcopyfrom(fx, fin, 0x7FFFFFFF); + gbfrewind(fx); + gbfclose(fin); + fin = fx; + + mmo_obj_ct = gbfgetuint16(fin); + DBG((sobj, "number of objects = %d\n", mmo_obj_ct)); + + i = gbfgetuint16(fin); + if (i != 0xFFFF) fatal(MYNAME ": Marker not equel to 0xFFFF!\n"); + + mmo_version = gbfgetuint16(fin); + DBG((sobj, "version = 0x%02X\n", mmo_version)); + + mmo_filemark = 0xFFFF0000UL | be_read16(&mmo_version); + DBG((sobj, "filemark = 0x%08X\n", mmo_filemark)); + + gbfseek(fin, -4, SEEK_CUR); + + while (! gbfeof(fin)) { /* main read loop */ + + (void) mmo_read_object(NULL); + + } + +#ifdef MMO_DBG + printf("\n" MYNAME ":---------------------------------------\n"); + printf(MYNAME ": EOF reached, nice!!!\n"); + printf(MYNAME ": =======================================\n\n"); +#endif +} + +/**************************************************************************/ + +static void +mmo_register_category_names(const char *name) +{ + char key[16]; + + snprintf(key, sizeof(key), "%d", mmo_object_id); + avltree_insert(category_names, name, xstrdup(key)); +} + + +static void +mmo_writestr(const char *str) +{ + int len = strlen(str); + + if (len > 254) { + len = len & 0x7FFF; + gbfputc(0xFF, fout); + gbfputint16(len, fout); + } + else gbfputc(len, fout); + if (len) gbfwrite(str, len, 1, fout); +} + + +static void +mmo_enum_waypt_cb(const waypoint *wpt) +{ + mmo_obj_ct++; +} + + +static void +mmo_enum_route_cb(const route_head *rte) +{ + mmo_obj_ct++; +} + + +static int +mmo_write_obj_mark(const char *sobj, const char *name) +{ + char *key; + gbuint16 nr; + char buf[16]; + int res; + + if (avltree_find(mmobjects, sobj, (void *)&key)) { + nr = (unsigned)atoi(key); + gbfputuint16(nr, fout); + } + else { + mmo_object_id++; + snprintf(buf, sizeof(buf), "%u", mmo_object_id); +#ifdef MMO_DBG + printf(MYNAME ": Object \"%s\" registered (id = 0x%04X)\n", sobj, mmo_object_id); +#endif + avltree_insert(mmobjects, sobj, xstrdup(buf)); + + gbfputuint32(mmo_filemark, fout); + gbfputuint16(strlen(sobj), fout); + gbfwrite(sobj, strlen(sobj), 1, fout); + } + + mmo_object_id++; + res = mmo_object_id; + mmo_writestr(name); + + return res; +} + + +static void +mmo_write_category(const char *sobj, const char *name) +{ + char *key; + gbuint16 nr; + + if (avltree_find(category_names, name, (void *)&key)) { + nr = (unsigned)atoi(key); + gbfputuint16(nr & 0x7FFF, fout); + } + else { + mmo_write_obj_mark(sobj, name); + mmo_register_category_names(name); + } +} + + +static int +mmo_write_obj_head(const char *sobj, const char *name, const time_t ctime, + const gpsdata_type type) +{ + int res; + + res = mmo_write_obj_mark(sobj, name); + + gbfputuint32(ctime, fout); + gbfputuint32(ctime, fout); + + gbfputc(0, fout); /* not locked */ + gbfputc(1, fout); /* visible */ + + switch(type) { + case trkdata: gbfputuint16(0x1E, fout); break; + case wptdata: gbfputuint16(0x3C, fout); break; + case rtedata: gbfputuint16(0x14, fout); break; + default: gbfputuint16(type, fout); break; + } + gbfputuint16(0x00, fout); + + return res; +} + + +static void +mmo_write_wpt_cb(const waypoint *wpt) +{ + char *str, *cx; + int objid; + time_t time; + int icon = 0; + + time = wpt->creation_time; + if (time < 0) time = 0; + + if (mmo_datatype == trkdata) { + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + gbfputc(0, fout); + gbfputuint32(time, fout); + if (wpt->altitude != unknown_alt) + gbfputflt(wpt->altitude, fout); + else + gbfputflt(0, fout); + + return; + } + + objid = mmo_write_obj_head("CObjWaypoint", (wpt->shortname) ? wpt->shortname : "Marks", time, wptdata); + mmo_register_object(objid, wpt, wptdata); + mmo_write_category("CCategory", "Marks"); // (mmo_datatype == rtedata) ? "Waypoints" : "Marks"); + + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + + if (mmo_datatype == rtedata) { + int i = mmo_get_objid(mmo_rte); + gbfputuint16(1, fout); /* two extra bytes */ + gbfputuint16(i & 0x7FFF, fout); + } + else + gbfputuint16(0, fout); /* extra bytes */ + + if (wpt->url && *wpt->url) { + str = xstrdup("_FILE_ "); + str = xstrappend(str, wpt->url); + str = xstrappend(str, "\n"); + } + else str = xstrdup(""); + + cx = wpt->description; + if (cx == NULL) cx = wpt->notes; + if (cx != NULL) { + char *kml = NULL; + + if (strcmp(wpt->session->name, "kml") == 0) { + utf_string tmp; + + tmp.utfstring = cx; + tmp.is_html = 1; + cx = kml = strip_html(&tmp); + } + str = xstrappend(str, cx); + if (kml) xfree(kml); + } + mmo_writestr(str); + xfree(str); + + gbfputuint32(0x01, fout); + if WAYPT_HAS(wpt, proximity) gbfputflt((int) wpt->proximity, fout); + else gbfputflt(0, fout); + + if (wpt->icon_descr) { + int i = 0; + + while (mmo_icon_value_table[i].icon) { + if (case_ignore_strcmp(wpt->icon_descr, mmo_icon_value_table[i].icon) == 0) { + icon = mmo_icon_value_table[i].value; + break; + } + i++; + } + } + gbfputuint32(icon, fout); + + mmo_writestr(""); /* name on gps */ + gbfputuint32(0x00, fout); +} + + +static void +mmo_write_rte_head_cb(const route_head *rte) +{ + int objid; + queue *elem, *tmp; + time_t time = 0x7FFFFFFF; + + if (rte->rte_waypt_ct <= 0) return; + + mmo_rte = (route_head *)rte; + + QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) { + waypoint *wpt = (waypoint *)elem; + + if ((wpt->creation_time > 0) && (wpt->creation_time < time)) + time = wpt->creation_time; + } + if (time == 0x7FFFFFFF) time = gpsbabel_time; + + objid = mmo_write_obj_head("CObjRoute", + (rte->rte_name) ? rte->rte_name : "Route", time, rtedata); + mmo_register_object(objid, rte, rtedata); + mmo_write_category("CCategory", "Route"); + gbfputc(0, fout); /* unknown */ + gbfputuint16(rte->rte_waypt_ct, fout); +} + + +static void +mmo_write_rte_tail_cb(const route_head *rte) +{ + queue *elem, *tmp; + + if (rte->rte_waypt_ct <= 0) return; + + if (rte->line_color.bbggrr < 0) { + gbfputuint32(0xFF, fout); /* color; default red */ + gbfputc(0x01, fout); /* Line width "normal" */ + gbfputc(0x00, fout); /* Line style "solid"*/ + gbfputc(0x00, fout); /* Transparency "Opaque" */ + } + else { + gbfputuint32(rte->line_color.bbggrr, fout); /* color */ + gbfputc(0x01, fout); /* Line width "normal" */ + gbfputc(0x00, fout); /* Line style "solid"*/ + gbfputc((255 - rte->line_color.opacity) / 51, fout); /* Transparency "Opaque" */ + } + + QUEUE_FOR_EACH(&rte->waypoint_list, elem, tmp) { + waypoint *wpt = (waypoint *)elem; + int objid = mmo_get_objid(wpt); + gbfputuint16(objid & 0x7FFF, fout); + } +} + + +static void +mmo_write_trk_head_cb(const route_head *trk) +{ + int objid; + + if (trk->rte_waypt_ct <= 0) return; + + objid = mmo_write_obj_head("CObjTrack", (trk->rte_name) ? trk->rte_name : "Track", gpsbabel_time, trkdata); + mmo_write_category("CCategory", "Track"); + gbfputuint16(trk->rte_waypt_ct, fout); + + mmo_register_object(objid, trk, trkdata); +} + + +static void +mmo_write_trk_tail_cb(const route_head *trk) +{ + if (trk->rte_waypt_ct <= 0) return; + + gbfputuint32(0x0A, fout); /* Min. update interval */ + gbfputflt(0, fout); + gbfputflt(0, fout); + gbfputuint32(0x0F, fout); /* Min. update distance */ + gbfputuint32(0xE10, fout); /* Track partition interval */ + gbfputuint32(0x00, fout); /* ??? */ + gbfputuint32(0x12C, fout); + + if (trk->line_color.bbggrr < 0) { + gbfputuint32(0xFF0000, fout); /* color; default blue */ + gbfputc(0x01, fout); /* Line width "normal" */ + gbfputc(0x00, fout); /* Line style "solid"*/ + gbfputc(0x00, fout); /* Transparency "Opaque" */ + } + else { + gbfputuint32(trk->line_color.bbggrr, fout); /* color */ + gbfputc(0x01, fout); /* Line width "normal" */ + gbfputc(0x00, fout); /* Line style "solid"*/ + gbfputc((255 - trk->line_color.opacity) / 51, fout); /* Transparency "Opaque" */ + } +} + +/**************************************************************************/ + +static void +mmo_wr_init(const char *fname) +{ + fout = gbfopen_le(fname, "wb", MYNAME); + + objects = avltree_init(0, MYNAME); + mmobjects = avltree_init(0, MYNAME); + category_names = avltree_init(0, MYNAME); + + mmo_object_id = 0x8000; + mmo_obj_ct = 1; /* ObjIcons always present */ + mmo_version = 0x12; /* we write as version 0x12 */ + mmo_filemark = 0xFFFFUL | (mmo_version << 16); +} + + +static void +mmo_wr_deinit(void) +{ + mmo_release_avltree(mmobjects, 0); + mmo_release_avltree(category_names, 0); + mmo_release_avltree(objects, 1); + + gbfclose(fout); +} + + +static void +mmo_write(void) +{ + int i; + + /* find out number of objects we have to write */ + waypt_disp_all(mmo_enum_waypt_cb); + route_disp_all(mmo_enum_route_cb, NULL, mmo_enum_waypt_cb); + track_disp_all(mmo_enum_route_cb, NULL, NULL); + + gbfputuint16(mmo_obj_ct, fout); + + mmo_write_obj_head("CObjIcons", "Unnamed object", gpsbabel_time, 0); + for (i = 0; i < 5; i++) gbfputuint16(0, fout); + + mmo_datatype = wptdata; + waypt_disp_all(mmo_write_wpt_cb); + mmo_datatype = rtedata; + route_disp_all(mmo_write_rte_head_cb, mmo_write_rte_tail_cb, mmo_write_wpt_cb); + mmo_datatype = trkdata; + track_disp_all(mmo_write_trk_head_cb, mmo_write_trk_tail_cb, mmo_write_wpt_cb); +} + +/**************************************************************************/ + +ff_vecs_t mmo_vecs = { + ff_type_file, + FF_CAP_RW_ALL, /* read and write waypoints, tracks and routes*/ + mmo_rd_init, + mmo_wr_init, + mmo_rd_deinit, + mmo_wr_deinit, + mmo_read, + mmo_write, + NULL, + mmo_args, + CET_CHARSET_MS_ANSI, 0 + +}; + +/**************************************************************************/ diff --git a/reference/memory-map.mmo b/reference/memory-map.mmo new file mode 100755 index 0000000000000000000000000000000000000000..5785270ff314d54d314ad090a73612329bfe0ffe GIT binary patch literal 21552 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 literal 0 HcmV?d00001 diff --git a/reference/memory-map~mmo.gpx b/reference/memory-map~mmo.gpx new file mode 100644 index 000000000..358aa6caf --- /dev/null +++ b/reference/memory-map~mmo.gpx @@ -0,0 +1,3180 @@ + + + + + + + 3 + B93 + B93 + Dot + + + + Altenburg-Umgehung + Altenburg-Umgehung + Altenburg-Umgehung + Dot + + + + Elsterberg + Piehlerstrasse + Piehlerstrasse + Dot + + + + Gosel + Gosel + Gosel + Dot + + + + Greiz + August-Bebel-Strasse + August-Bebel-Strasse + Dot + + + + Jahnstrasse + Jahnstrasse 11 + Jahnstrasse 11 + Dot + + + + Liebknechtstrasse + Liebknechtstrasse 90 + Liebknechtstrasse 90 + Dot + + + + NARVA + Start + Start + http://www.narva-light.de + Flag + + + + Völkerschlachtdenkmal + P+R Am Völkerschlachtdenkmal P+R + P+R Am Völkerschlachtdenkmal P+R + http://www.leipzig.de + Flag + + + + Mark + Mark + Mark + Flag + + + NARVA-Leipzig + + + NARVA + + + + Liebknechtstrasse + + + + Jahnstrasse + + + + Elsterberg + + + + Greiz + + + + Gosel + + + + 3 + + + + Altenburg-Umgehung + + + + Völkerschlachtdenkmal + + + + Track + + + 0.000000 + + + 0.000000 + + + 0.000000 + + + 0.000000 + + + 0.000000 + + + 0.000000 + + + 0.000000 + + + + + ACTIVE LOG 001 + + + 146.257812 + + + + 145.777100 + + + + 146.738403 + + + + 141.931763 + + + + 141.931763 + + + + 141.451050 + + + + 141.931763 + + + + 142.412476 + + + + 141.931763 + + + + 142.893066 + + + + 142.412476 + + + + 134.241211 + + + + 135.683105 + + + + 136.163940 + + + + 136.644653 + + + + 139.047852 + + + + 142.412476 + + + + + + ACTIVE LOG 002 + + + 136.163940 + + + + 147.699707 + + + + 146.738403 + + + + 154.428955 + + + + 151.064209 + + + + 144.335205 + + + + 142.412476 + + + + 134.241211 + + + + 135.202515 + + + + 135.683105 + + + + 135.202515 + + + + + + ACTIVE LOG 003 + + + 149.622314 + + + + + + ACTIVE LOG 004 + + + 160.677490 + + + + + + ACTIVE LOG 005 + + + 161.158203 + + + + + + ACTIVE LOG 006 + + + 161.158203 + + + + 153.948364 + + + + 148.180420 + + + + 138.567261 + + + + 144.815796 + + + + 133.760498 + + + + 130.876709 + + + + 130.395996 + + + + 131.837891 + + + + 143.854370 + + + + 147.218994 + + + + 145.296387 + + + + 145.296387 + + + + 135.202515 + + + + 134.721924 + + + + 136.163940 + + + + 135.202515 + + + + 138.567261 + + + + 138.567261 + + + + 140.970459 + + + + 139.528442 + + + + 140.489868 + + + + 151.544922 + + + + 152.025757 + + + + 155.390259 + + + + 148.661011 + + + + 149.622314 + + + + 150.583618 + + + + 150.583618 + + + + 149.622314 + + + + 149.622314 + + + + 149.622314 + + + + 149.622314 + + + + 143.373657 + + + + 141.451050 + + + + 143.373657 + + + + 138.567261 + + + + 138.567261 + + + + 138.086548 + + + + 138.567261 + + + + 143.854370 + + + + 144.815796 + + + + + + ACTIVE LOG 007 + + + 150.583618 + + + + 152.025757 + + + + 136.644653 + + + + 133.760498 + + + + 133.760498 + + + + 135.202515 + + + + 131.837891 + + + + 136.644653 + + + + 136.163940 + + + + 134.721924 + + + + 133.760498 + + + + 133.279907 + + + + 131.837891 + + + + 128.954102 + + + + 127.511963 + + + + 126.550659 + + + + 125.589355 + + + + 124.628052 + + + + 123.666748 + + + + 123.186157 + + + + 123.186157 + + + + 120.782837 + + + + 121.263550 + + + + 120.302124 + + + + 118.379395 + + + + 116.937500 + + + + 115.014893 + + + + 114.053589 + + + + 113.092285 + + + + 112.611572 + + + + 112.130981 + + + + 112.611572 + + + + 112.611572 + + + + 113.092285 + + + + 113.572998 + + + + 113.092285 + + + + 112.611572 + + + + 112.611572 + + + + 115.014893 + + + + 115.014893 + + + + 114.053589 + + + + 115.976196 + + + + 115.976196 + + + + 115.976196 + + + + 115.014893 + + + + 114.534180 + + + + 112.130981 + + + + 112.130981 + + + + 109.727661 + + + + 109.727661 + + + + 108.766235 + + + + 110.208252 + + + + 110.208252 + + + + 110.208252 + + + + 111.169556 + + + + 111.650269 + + + + 112.611572 + + + + 112.130981 + + + + 112.130981 + + + + 111.650269 + + + + 110.208252 + + + + 108.766235 + + + + 107.324341 + + + + 106.843628 + + + + 107.324341 + + + + 107.805054 + + + + 107.805054 + + + + 107.324341 + + + + 109.727661 + + + + 110.208252 + + + + 111.169556 + + + + 111.650269 + + + + 113.092285 + + + + 115.014893 + + + + 115.976196 + + + + 114.534180 + + + + 113.092285 + + + + 112.130981 + + + + 112.130981 + + + + 112.611572 + + + + 111.169556 + + + + 109.727661 + + + + 109.246948 + + + + 109.246948 + + + + 110.208252 + + + + 110.208252 + + + + 110.688843 + + + + 111.650269 + + + + 112.130981 + + + + 112.130981 + + + + 112.130981 + + + + 112.611572 + + + + 112.611572 + + + + 113.092285 + + + + 113.092285 + + + + 113.092285 + + + + 113.092285 + + + + 113.092285 + + + + 113.092285 + + + + 113.092285 + + + + 114.053589 + + + + 114.534180 + + + + 115.976196 + + + + 117.418213 + + + + 116.456787 + + + + 116.937500 + + + + 116.937500 + + + + 116.456787 + + + + 116.937500 + + + + 116.937500 + + + + 116.937500 + + + + 117.418213 + + + + 118.379395 + + + + 119.821411 + + + + 120.302124 + + + + 120.302124 + + + + 122.705444 + + + + 122.224731 + + + + 122.224731 + + + + 122.224731 + + + + 122.705444 + + + + 122.705444 + + + + 123.666748 + + + + 124.628052 + + + + 123.186157 + + + + 121.744141 + + + + 121.744141 + + + + 122.705444 + + + + 120.782837 + + + + 121.744141 + + + + 122.705444 + + + + 119.821411 + + + + 122.705444 + + + + 128.473389 + + + + 133.760498 + + + + 138.567261 + + + + 142.893066 + + + + 143.373657 + + + + 142.893066 + + + + 141.451050 + + + + 137.605835 + + + + 136.644653 + + + + 136.644653 + + + + 135.683105 + + + + 135.683105 + + + + 136.644653 + + + + 137.605835 + + + + 138.567261 + + + + 139.528442 + + + + 140.489868 + + + + 141.451050 + + + + 142.412476 + + + + 142.412476 + + + + 142.412476 + + + + 142.412476 + + + + 142.412476 + + + + 143.373657 + + + + 144.335205 + + + + 145.296387 + + + + 145.777100 + + + + 145.777100 + + + + 146.257812 + + + + 146.257812 + + + + 147.218994 + + + + 148.661011 + + + + 149.622314 + + + + 151.544922 + + + + 153.467651 + + + + 154.909546 + + + + 155.870972 + + + + 156.832153 + + + + 158.274170 + + + + 159.716187 + + + + 159.235474 + + + + 158.754761 + + + + 158.274170 + + + + 156.351562 + + + + 156.351562 + + + + 154.909546 + + + + 154.428955 + + + + 153.948364 + + + + 152.986938 + + + + 152.025757 + + + + 151.544922 + + + + 152.025757 + + + + 151.064209 + + + + 149.622314 + + + + 147.218994 + + + + 144.815796 + + + + 143.854370 + + + + 143.373657 + + + + 143.373657 + + + + 143.373657 + + + + 142.412476 + + + + 141.451050 + + + + 139.047852 + + + + 135.202515 + + + + 133.279907 + + + + 133.760498 + + + + 134.241211 + + + + 137.125244 + + + + 140.489868 + + + + 142.893066 + + + + 144.815796 + + + + 146.738403 + + + + 148.180420 + + + + 149.141602 + + + + 150.583618 + + + + 151.064209 + + + + 151.064209 + + + + 151.064209 + + + + 150.103027 + + + + 149.622314 + + + + 150.103027 + + + + 150.583618 + + + + 151.064209 + + + + 151.544922 + + + + 152.025757 + + + + 152.986938 + + + + 154.428955 + + + + 154.428955 + + + + 154.428955 + + + + 154.909546 + + + + 147.699707 + + + + 141.931763 + + + + 139.047852 + + + + 137.125244 + + + + 132.799316 + + + + 130.876709 + + + + 129.915283 + + + + 129.915283 + + + + 129.915283 + + + + 129.915283 + + + + 131.357300 + + + + 132.318604 + + + + 132.799316 + + + + 133.760498 + + + + 134.721924 + + + + 135.683105 + + + + 135.202515 + + + + 135.202515 + + + + 132.318604 + + + + 133.760498 + + + + 135.683105 + + + + 137.125244 + + + + 139.528442 + + + + 140.009155 + + + + 140.970459 + + + + 140.970459 + + + + 141.931763 + + + + 142.412476 + + + + 142.412476 + + + + 142.893066 + + + + 143.373657 + + + + 143.373657 + + + + 143.373657 + + + + 143.854370 + + + + 144.815796 + + + + 147.699707 + + + + 146.738403 + + + + 146.257812 + + + + 145.777100 + + + + 145.296387 + + + + 146.738403 + + + + 147.699707 + + + + 148.661011 + + + + 150.103027 + + + + 152.506348 + + + + 154.909546 + + + + 156.832153 + + + + 157.312866 + + + + 157.793579 + + + + 157.793579 + + + + 158.274170 + + + + 158.274170 + + + + 159.235474 + + + + 162.119507 + + + + 164.042114 + + + + 165.003418 + + + + 165.003418 + + + + 164.042114 + + + + 163.080811 + + + + 162.119507 + + + + 162.600098 + + + + 163.561523 + + + + 162.600098 + + + + 161.638916 + + + + 160.196899 + + + + 156.832153 + + + + 152.506348 + + + + 155.390259 + + + + 156.351562 + + + + 155.870972 + + + + 152.025757 + + + + 149.622314 + + + + 147.699707 + + + + 146.738403 + + + + 146.738403 + + + + 146.257812 + + + + 145.777100 + + + + 144.815796 + + + + 144.335205 + + + + 144.335205 + + + + 144.335205 + + + + 144.335205 + + + + 143.854370 + + + + 144.335205 + + + + 144.335205 + + + + 144.335205 + + + + 144.815796 + + + + 145.296387 + + + + 145.777100 + + + + 146.257812 + + + + 146.738403 + + + + 146.738403 + + + + 146.257812 + + + + 146.738403 + + + + 146.738403 + + + + 146.257812 + + + + 145.777100 + + + + 147.218994 + + + + 147.218994 + + + + 147.218994 + + + + 147.218994 + + + + 147.218994 + + + + 148.180420 + + + + 147.699707 + + + + 148.180420 + + + + 149.622314 + + + + 150.103027 + + + + 150.103027 + + + + 149.622314 + + + + 148.180420 + + + + 148.180420 + + + + 148.661011 + + + + 149.141602 + + + + 149.141602 + + + + 149.141602 + + + + 148.180420 + + + + 149.622314 + + + + 152.986938 + + + + 154.909546 + + + + 156.351562 + + + + 158.274170 + + + + 161.638916 + + + + 164.522705 + + + + 164.042114 + + + + 161.638916 + + + + 159.716187 + + + + 158.754761 + + + + 160.196899 + + + + 161.158203 + + + + 161.638916 + + + + 162.119507 + + + + 162.600098 + + + + 164.042114 + + + + 165.003418 + + + + 165.964722 + + + + 166.926025 + + + + 166.926025 + + + + 165.484131 + + + + 166.926025 + + + + 168.368042 + + + + 170.771362 + + + + 172.213257 + + + + 173.655273 + + + + 176.058594 + + + + 180.384521 + + + + 186.152466 + + + + 189.516968 + + + + 192.401123 + + + + 194.323730 + + + + 194.804321 + + + + 193.843018 + + + + 190.478394 + + + + 187.113770 + + + + 186.633179 + + + + 185.671753 + + + + 184.710571 + + + + 182.787842 + + + + 181.826416 + + + + 179.903809 + + + + 177.500610 + + + + 174.616577 + + + + 172.693970 + + + + 171.732666 + + + + 172.213257 + + + + 174.135864 + + + + 177.020020 + + + + 183.749023 + + + + 189.516968 + + + + 193.843018 + + + + 197.688232 + + + + 200.091675 + + + + 200.572266 + + + + 199.130127 + + + + 197.207520 + + + + 195.284912 + + + + 193.362305 + + + + 191.439575 + + + + 191.439575 + + + + 193.362305 + + + + 197.207520 + + + + 202.014282 + + + + 207.301392 + + + + 214.030640 + + + + 217.395386 + + + + 219.798584 + + + + 222.201782 + + + + 224.124512 + + + + 222.682495 + + + + 221.721191 + + + + 220.759888 + + + + 220.279175 + + + + 220.759888 + + + + 222.201782 + + + + 224.605225 + + + + 226.527832 + + + + 227.008545 + + + + 227.008545 + + + + 226.527832 + + + + 226.527832 + + + + 226.047119 + + + + 225.566528 + + + + 226.047119 + + + + 227.008545 + + + + 227.489136 + + + + 227.969727 + + + + 226.047119 + + + + 222.682495 + + + + 221.240601 + + + + 218.356567 + + + + 216.914673 + + + + 215.472656 + + + + 217.875977 + + + + 220.759888 + + + + 224.605225 + + + + 226.527832 + + + + 229.892334 + + + + 232.295776 + + + + 231.814941 + + + + 231.334351 + + + + 228.931152 + + + + 224.605225 + + + + 220.759888 + + + + 216.914673 + + + + 213.069336 + + + + 206.820679 + + + + 202.494873 + + + + 199.130127 + + + + 196.246338 + + + + 194.323730 + + + + 193.843018 + + + + 193.843018 + + + + 193.362305 + + + + 191.920288 + + + + 189.516968 + + + + 187.113770 + + + + 184.710571 + + + + 182.307129 + + + + 182.307129 + + + + 182.307129 + + + + 182.787842 + + + + 182.787842 + + + + 182.307129 + + + + 182.307129 + + + + 182.787842 + + + + 183.268433 + + + + 184.229858 + + + + 183.749023 + + + + 183.749023 + + + + 183.749023 + + + + 183.749023 + + + + 183.268433 + + + + 183.268433 + + + + 183.268433 + + + + 183.268433 + + + + 183.268433 + + + + 183.749023 + + + + 183.268433 + + + + 183.749023 + + + + 183.749023 + + + + 184.229858 + + + + 184.229858 + + + + 183.749023 + + + + 183.749023 + + + + 184.710571 + + + + 185.191162 + + + + 185.191162 + + + + 185.671753 + + + + 185.191162 + + + + 185.191162 + + + + 185.671753 + + + + 185.671753 + + + + 186.633179 + + + + 186.633179 + + + + 187.113770 + + + + 187.113770 + + + + 188.075073 + + + + 189.516968 + + + + 188.075073 + + + + 188.555786 + + + + 188.555786 + + + + 189.516968 + + + + 189.516968 + + + + 189.997681 + + + + 189.997681 + + + + 189.516968 + + + + 189.997681 + + + + 191.439575 + + + + 192.881714 + + + + 194.323730 + + + + 195.765625 + + + + 195.284912 + + + + 194.804321 + + + + 193.362305 + + + + 192.881714 + + + + 192.881714 + + + + 193.362305 + + + + 192.881714 + + + + 190.958984 + + + + 189.516968 + + + + 189.516968 + + + + 188.555786 + + + + 188.555786 + + + + 188.555786 + + + + 188.555786 + + + + 189.516968 + + + + 190.958984 + + + + 189.516968 + + + + 189.036377 + + + + 188.555786 + + + + 188.555786 + + + + 188.075073 + + + + 188.075073 + + + + 188.555786 + + + + 189.516968 + + + + 189.997681 + + + + 190.478394 + + + + 189.516968 + + + + 189.997681 + + + + 190.478394 + + + + 191.920288 + + + + 191.920288 + + + + 191.920288 + + + + 191.439575 + + + + 191.439575 + + + + 191.439575 + + + + 190.958984 + + + + 191.439575 + + + + 191.439575 + + + + 191.920288 + + + + 192.401123 + + + + 192.401123 + + + + 192.401123 + + + + 191.920288 + + + + 191.439575 + + + + 191.920288 + + + + 193.362305 + + + + 195.284912 + + + + 197.688232 + + + + 198.168945 + + + + 199.130127 + + + + 199.610840 + + + + 199.130127 + + + + 197.688232 + + + + 197.207520 + + + + 197.688232 + + + + 198.168945 + + + + 198.649536 + + + + 198.168945 + + + + 198.168945 + + + + 198.168945 + + + + 197.207520 + + + + 197.207520 + + + + 197.207520 + + + + 197.207520 + + + + 198.168945 + + + + 197.688232 + + + + 197.688232 + + + + 199.130127 + + + + 200.091675 + + + + 201.052856 + + + + 201.052856 + + + + 201.533569 + + + + 200.091675 + + + + 201.052856 + + + + 200.091675 + + + + 199.610840 + + + + 196.726929 + + + + 196.246338 + + + + 195.284912 + + + + 194.804321 + + + + 194.804321 + + + + 195.284912 + + + + 197.688232 + + + + 198.168945 + + + + 197.688232 + + + + 197.688232 + + + + 198.168945 + + + + 198.649536 + + + + 198.649536 + + + + 199.130127 + + + + 199.610840 + + + + 200.091675 + + + + 201.052856 + + + + 201.052856 + + + + 202.494873 + + + + 204.417480 + + + + 206.340088 + + + + 207.782104 + + + + 210.666016 + + + + 213.069336 + + + + 214.511230 + + + + 214.030640 + + + + 213.550049 + + + + 214.511230 + + + + 215.953247 + + + + 217.395386 + + + + 220.759888 + + + + 221.240601 + + + + 221.240601 + + + + 221.240601 + + + + 220.279175 + + + + 219.317993 + + + + 217.875977 + + + + 217.875977 + + + + 218.356567 + + + + 218.356567 + + + + 217.395386 + + + + 218.356567 + + + + 222.682495 + + + + 227.008545 + + + + 231.334351 + + + + 238.544312 + + + + 234.699097 + + + + 231.334351 + + + + 229.892334 + + + + 228.931152 + + + + 228.450439 + + + + 227.969727 + + + + 226.047119 + + + + 222.201782 + + + + 221.240601 + + + + 215.953247 + + + + 214.030640 + + + + 212.108032 + + + + 212.588623 + + + + 211.627441 + + + + 207.782104 + + + + 206.340088 + + + + 204.417480 + + + + 204.417480 + + + + 204.417480 + + + + 204.898071 + + + + 205.859497 + + + + 206.340088 + + + + 207.301392 + + + + 207.782104 + + + + 206.820679 + + + + 206.340088 + + + + 205.378784 + + + + 205.859497 + + + + 207.782104 + + + + + + ACTIVE LOG 008 + + + 203.936890 + + + + 203.936890 + + + + 209.224121 + + + + 221.721191 + + + + + + ACTIVE LOG 009 + + + 218.837280 + + + + 198.649536 + + + + 217.395386 + + + + 209.704834 + + + + 208.262817 + + + + 208.262817 + + + + + diff --git a/vecs.c b/vecs.c index 108ae64c5..828caeae1 100644 --- a/vecs.c +++ b/vecs.c @@ -151,6 +151,7 @@ extern ff_vecs_t ggv_ovl_vecs; extern ff_vecs_t jtr_vecs; #endif extern ff_vecs_t sbp_vecs; +extern ff_vecs_t mmo_vecs; static vecs_t vec_list[] = { @@ -862,6 +863,12 @@ vecs_t vec_list[] = { "NaviGPS GT-31/BGT-31 datalogger (.sbp)", "sbp" }, + { + &mmo_vecs, + "mmo", + "Memory-Map overlay files (.mmo)", + "mmo" + }, #endif // MAXIMAL_ENABLED -- 2.30.2